package com.jokerku.mini.schedule.event;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONValidator;
import com.jokerku.mini.schedule.common.Constants;
import com.jokerku.mini.schedule.domain.ExecOrder;
import com.jokerku.mini.schedule.domain.Instruct;
import com.jokerku.mini.schedule.domain.ZkPath;
import com.jokerku.mini.schedule.service.ZkCuratorServer;
import com.jokerku.mini.schedule.task.CronTaskRegister;
import com.jokerku.mini.schedule.task.ScheduleRunnable;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

/**
 * @Author: guzq
 * @CreateTime: 2023/06/19 14:39
 * @Description: 后台操作事件
 * @Version: 1.0
 */
public class InstructEventListener implements ScheduleEventListener<TreeCacheEvent> {

    private static final Logger logger = LoggerFactory.getLogger(InstructEventListener.class);

    @Override
    public void consumeEvent(TreeCacheEvent treeCacheEvent) {
        byte[] data = treeCacheEvent.getData().getData();
        if (null == data || data.length < 1) {
            return;
        }
        String json = new String(data, Constants.Global.CHARSET);
        if (!JSONValidator.from(json).validate()) {
            return;
        }
        Instruct instruct = JSON.parseObject(json, Instruct.class);

        ApplicationContext applicationContext = Constants.Global.applicationContext;
        TreeCacheEvent.Type type =treeCacheEvent.getType();
        try {
            switch (type) {
                // 节点添加/修改事件
                case NODE_ADDED:
                case NODE_UPDATED: {
                    if (!Constants.Global.ip.equals(instruct.getIp())
                            || !Constants.Global.scheduleServerId.equals(instruct.getSchedulerServerId())) {
                        return;
                    }
                    if (!applicationContext.containsBean(instruct.getBeanName())) {
                        return;
                    }
                    Object cronBean = applicationContext.getBean(instruct.getBeanName());
                    CronTaskRegister cronTaskRegister = applicationContext.getBean("mini-schedule-cron-task-register", CronTaskRegister.class);

                    ExecOrder execOrder = new ExecOrder();
                    execOrder.setBeanName(instruct.getBeanName());
                    execOrder.setMethodName(instruct.getMethodName());
                    String pathRootServerIpClassMethodStatus = ZkPath.getServerTaskClassMethodStatusPath(execOrder);
                    ScheduleRunnable scheduleRunnable = new ScheduleRunnable(cronBean, execOrder);
                    // 执行命令
                    switch (instruct.getStatus()) {
                        case Constants.InstructStatus.STOP: {
                            cronTaskRegister.removeCronTask(scheduleRunnable);
                            ZkCuratorServer.setData(Constants.Global.client, pathRootServerIpClassMethodStatus, "0");
                            logger.info("mini schedule task stop {}-{}", instruct.getBeanName(), instruct.getMethodName());
                            break;
                        }
                        case Constants.InstructStatus.START: {
                            cronTaskRegister.addCornTask(scheduleRunnable, instruct.getCron());
                            ZkCuratorServer.setData(Constants.Global.client, pathRootServerIpClassMethodStatus, "1");
                            logger.info("mini schedule task start {}-{}", instruct.getBeanName(), instruct.getMethodName());
                            break;
                        }
                        case Constants.InstructStatus.REFRESH: {
                            cronTaskRegister.removeCronTask(scheduleRunnable);
                            cronTaskRegister.addCornTask(scheduleRunnable, instruct.getCron());
                            ZkCuratorServer.setData(Constants.Global.client, pathRootServerIpClassMethodStatus, "1");
                            logger.info("mini schedule task refresh {}-{}", instruct.getBeanName(), instruct.getMethodName());
                            break;
                        }
                        default:
                            break;
                    }
                    break;
                }
                case NODE_REMOVED: {
                    // ignore
                    break;
                }
                default:
                    break;
            }

            // 清空数据
            ZkCuratorServer.setData(Constants.Global.client, ZkPath.geExecPath(), "");
        } catch (Exception e) {
            logger.error("Consume instruct event error", e);
        }
    }
}
